package cn.lh.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * ECC算法工具类
 */
public class ECCUtil {
    /**
     * 算法名称
     */
    private static final String ALGORITHM = "ECDSA";

    /**
     * BouncyCastle provider
     */
    private static final String PROVIDER = "BC";

    private static final String ENCRYPT_ALGORITHM = "ECIES";

    /**
     * 密钥交换算法
     */
    private static final String SHARE_KEY_ALGORITHM = "ECDH";

    /**
     * 签名算法
     */
    private static final String SIGN_PROVIDER = "SHA256withECDSA";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 生产公私钥对
     *
     * @return ECC公私钥
     * @throws Exception
     */
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);
        // 指定EC曲线类型生成密钥对
        ECGenParameterSpec spec = new ECGenParameterSpec("curve25519");
        keyPairGenerator.initialize(spec, SecureRandom.getInstance("SHA1PRNG"));
        return keyPairGenerator.generateKeyPair();
    }
    /**
     * 生成密钥对
     * @param keysize 密钥长度
     * @return
     */
    public static KeyPair generateECCKeyPair(int keysize) {
        try {
                // 获取指定算法的密钥对生成器
                KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC");
            // 初始化密钥对生成器（指定密钥长度, 使用默认的安全随机数源）
            generator.initialize(keysize);
            // 随机生成一对密钥（包含公钥和私钥）
            return generator.generateKeyPair();
        } catch (Exception e) {
                e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        KeyPair keyPair = generateKeyPair();
        PrivateKey aPrivate = keyPair.getPrivate();
        PublicKey aPublic = keyPair.getPublic();
        System.err.println("aaa");
    }

    /**
     * 读取公钥（base64编码）
     * @param keyPair
     * @return
     */
    public static String getPublicKey(KeyPair keyPair) {
        return Base64.toBase64String(keyPair.getPublic().getEncoded());
    }

    /**
     * 读取私钥（base64编码）
     * @param keyPair
     * @return
     */
    public static String getPrivateKey(KeyPair keyPair) {
        return Base64.toBase64String(keyPair.getPrivate().getEncoded());
    }

    /**
     * 构建公钥对象（输入为base64编码字符串）
     * @param keyStr
     * @return
     * @throws Exception
     */
    public static PublicKey str2PublicKey(String keyStr) throws Exception {
        byte[] publicKey = Base64.decode(keyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 构建私钥对象（输入为base64编码字符串）
     * @param keyStr
     * @return
     * @throws Exception
     */
    public static PrivateKey str2PrivateKey(String keyStr) throws Exception {
        byte[] privateKey = Base64.decode(keyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, PROVIDER);
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 加密数据
     * @param publicKey 公钥
     * @param data 数据
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
        Cipher cipher = Cipher.getInstance(ENCRYPT_ALGORITHM, PROVIDER);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 解密数据
     * @param privateKey 私钥
     * @param data 数据
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
        Cipher cipher = Cipher.getInstance(ENCRYPT_ALGORITHM, PROVIDER);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 数据签名
     * @param privateKey 私钥
     * @param data 数据
     * @return
     * @throws Exception
     */
    public static byte[] sign(PrivateKey privateKey, byte[] data) throws Exception {
        Signature signature = Signature.getInstance(SIGN_PROVIDER);
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }

    /**
     * 数据验签
     * @param publicKey 公钥
     * @param data 数据
     * @param sign 数据签名
     * @return
     * @throws Exception
     */
    public static boolean verify(PublicKey publicKey, byte[] data, byte[] sign) throws Exception {
        Signature signature = Signature.getInstance(SIGN_PROVIDER);
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(sign);
    }

    /**
     * 生成共享密钥：用于密钥交换，客户端和服务器端双方各自生成一对公私钥，然后客户端使用自己的私钥和服务器的公钥生成一个共享秘钥，
     * 服务端使用自己的私钥和客户端的公钥生成一个共享秘钥，这两个秘钥结果相同，可用于对称加密
     * @param privateKey
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] genShareKey(PublicKey publicKey, PrivateKey privateKey) throws Exception {
        KeyAgreement keyAgreement = KeyAgreement.getInstance(SHARE_KEY_ALGORITHM, PROVIDER);
        keyAgreement.init(privateKey);
        keyAgreement.doPhase(publicKey, true);
        return keyAgreement.generateSecret();
    }
}